package com.jungle.client.channel;

import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;

import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.*;

public class TypeHelper {
    /**
     * 将给定的类型包装为JSON结果类型
     * 此方法用于将预期的类型转换为一个统一的JSON结果类型，以便在输出时保持一致的格式
     *
     * @param type 需要包装的类型
     * @return 包装后的类型
     */
    public static Type wrappedType(Type type) {
        return toJsonResult(TypeToken.of(type)).getType();
    }
    public static Type wrappedType(TypeToken typeToken) {
        return toJsonResult(typeToken).getType();
    }

    /**
     * 将给定的TypeToken转换为JsonResult类包裹的TypeToken
     *
     * @param <K>       泛型参数，表示JsonResult中数据的类型
     * @param typeToken 传入的TypeToken，代表泛型K的类型
     * @return 返回一个TypeToken<JsonResult < K>>对象，用于表示JsonResult<K>类型
     */
    public static <K> TypeToken<JsonResult<K>> toJsonResult(TypeToken<K> typeToken) {
        // 创建并返回一个新的TypeToken<JsonResult<K>>实例
        // 使用匿名内部类的方式，重写where方法，指定泛型参数K的具体类型
        TypeToken<JsonResult<K>> typeBase = new TypeToken<>() {
        };
        return typeBase.where(new TypeParameter<K>() {
        }, typeToken);
    }
    public static <K> TypeToken<JsonResult<List<K>>> toListJsonResult(TypeToken<K> typeToken) {
        // 创建并返回一个新的TypeToken<JsonResult<K>>实例
        // 使用匿名内部类的方式，重写where方法，指定泛型参数K的具体类型
        return (new TypeToken<JsonResult<List<K>>>() {
        }).where(new TypeParameter<K>() {
        }, typeToken);
    }

    /**
     * 根据给定的Type类型，如果类型是参数化类型或数组类型，则返回一个空的实例。
     * 对于参数化类型，返回其原始类型的一个空实例；对于数组类型，返回一个空数组。
     * 如果给定的Type既不是参数化类型也不是数组类型，则返回null。
     *
     * @param type 需要创建空实例的Type对象。可以是参数化类型或类类型（包括数组类）。
     * @return 根据给定Type类型返回的空实例，如果无法处理则返回null。
     */
    public static Object emptyType(Type type) {
        // 判断类型是否为参数化类型
        if (type instanceof ParameterizedType) {
            ParameterizedType pType = (ParameterizedType) type;
            Type rawType = pType.getRawType(); // 获取参数化类型的原始类型

            Class rawClass = (Class) rawType;
            if (isMatch(rawClass, List.class)) {
                return new ArrayList<>();
            } else if (isMatch(rawClass, Set.class)) {
                return new HashSet<>();
            } else if (isMatch(rawClass, Map.class)) {
                return new HashMap<>();
            } else if (rawClass.equals(TreeMap.class)) {
                return new TreeMap<>();
            }
        } else if (type instanceof Class<?> clazz) {
            if (clazz.isArray()) {
                // 创建一个空数组
                return Array.newInstance(clazz.getComponentType(), 0);
            } else if (clazz.equals(BigDecimal.class)) {
                //
                return BigDecimal.ZERO;
            } else if (clazz.equals(Number.class)) {
                return 0;
            } else if (clazz.equals(Boolean.class)) {
                //
                return Boolean.FALSE;
            }
        }
        return null;
    }

    /**
     * 判断给定的类是否与目标类匹配。
     * 这个方法判断的条件是：目标类是否可以被指定的类所赋值，或者目标类是否实现了指定类的接口。
     *
     * @param clazz       指定的类，用来作为判断的标准。
     * @param targetClass 目标类，需要被判断是否与指定类匹配。
     * @return 返回一个布尔值，如果目标类与指定类匹配，则返回true；否则返回false。
     */
    private static boolean isMatch(Class clazz, Class targetClass) {
        // 判断目标类是否可以被指定的类所赋值，或者目标类是否实现了指定类的接口
        return clazz.isAssignableFrom(targetClass) || Arrays.asList(clazz.getInterfaces()).contains(targetClass);
    }
}
